//
// Created by edward on 23-3-20.
//

#include "Camera.h"
#include "Shader.h"

Camera::Camera(const glm::vec3 &pos, float y, float p, const glm::vec3 &up, float speed)
    : cameraPos(pos)
    , yaw(y)
    , pitch(p)
    , cameraUp(up)
    , cameraSpeed(speed)
    , sensitivity(0.05f)
    {
    updateDir();
}

void Camera::lookAt(Shader *shader) const {
    shader->setViewMatrix(glm::lookAt(cameraPos, cameraPos + cameraDir, cameraUp));
    shader->set("viewPos", cameraPos);
}

void Camera::move(float deltaTime, Camera::Dir d) {
    float speed = deltaTime * cameraSpeed;
    switch (d) {
        case Dir::FORWARD:
            cameraPos += speed * cameraDir;
            break;
        case Dir::BACKWARD:
            cameraPos -= speed * cameraDir;
            break;
        case Dir::LEFT:
            cameraPos -= speed * cameraRight;
            break;
        case Dir::RIGHT:
            cameraPos += speed * cameraRight;
            break;
        case Dir::UP:
            cameraPos += speed * cameraUp;
            break;
        case Dir::DOWN:
            cameraPos -= speed * cameraUp;
            break;
    }
}

void Camera::changeDir(float xoffset, float yoffset) {
    /// 把角度转换成弧度，并称上对应的系数0.1，之所以不预先处理是因为避免浮点数的精度问题
    yaw += glm::radians(xoffset * sensitivity);
    pitch += glm::radians(yoffset * sensitivity);
    updateDir();
}

void Camera::updateDir() {
    /// avoid LookAt flip
    constexpr float kMaxDegree = M_PI_2 - 0.5;
    if (pitch > kMaxDegree) pitch = kMaxDegree;
    if (pitch < -kMaxDegree) pitch = -kMaxDegree;

    cameraDir = glm::normalize(glm::vec3(cos(yaw) * cos(pitch), sin(pitch), sin(yaw) * cos(pitch)));
    cameraRight = glm::normalize(glm::cross(cameraDir, cameraUp));
}

const glm::vec3 &Camera::getCameraPos() const {
    return cameraPos;
}

const glm::vec3 &Camera::getCameraDir() const {
    return cameraDir;
}
